package com.powernode.config;

import com.powernode.config.filter.TokenFilter;
import com.powernode.config.handler.AppAccessDeniedHandler;
import com.powernode.config.handler.AppAuthenticationFailureHandler;
import com.powernode.config.handler.AppAuthenticationSuccessHandler;
import com.powernode.config.handler.AppLogoutSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.List;

/**
 * Security 安全框架配置类
 */
@Configuration
@EnableMethodSecurity
public class SecurityConfig {

    @Autowired
    private AppAuthenticationSuccessHandler appAuthenticationSuccessHandler;

    @Autowired
    private AppAuthenticationFailureHandler appAuthenticationFailureHandler;

    @Autowired
    private AppLogoutSuccessHandler appLogoutSuccessHandler;

    @Autowired
    private AppAccessDeniedHandler appAccessDeniedHandler;

    @Autowired
    private TokenFilter tokenFilter;


    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        return httpSecurity
                // 登录表单配置
                .formLogin((formLogin) -> {
                    formLogin
                            .usernameParameter("loginAct")  // 登录帐号的用户名参数名
                            .passwordParameter("loginPwd")  // 登录帐号的密码参数名
                            .loginProcessingUrl("/api/login")   // 处理登录请求的url
                            .successHandler(appAuthenticationSuccessHandler)   // 登录成功处理器
                            .failureHandler(appAuthenticationFailureHandler); // 登录失败处理器
                })
                // 其它请求配置
                .authorizeHttpRequests((authorizeHttpRequests) -> {
                    authorizeHttpRequests
                            .anyRequest().authenticated();  // 所有请求都需要进行身份认证
                })
                // 关闭跨站请求伪造
                .csrf(csrf -> csrf.disable())
                .cors((cors) -> {
                    cors.configurationSource(corsConfigurationSource()); // 指定CORS配置源

                })
                // 关闭session使用策略
                .sessionManagement((sessionManagement) -> {
                    sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
                })
                // 登出配置
                .logout((logout) -> {
                    logout.logoutUrl("/api/logout");
                    logout.logoutSuccessHandler(appLogoutSuccessHandler);  // 登出成功处理器
                })
                .exceptionHandling((exceptionHandling) -> {
                    // 认证异常处理
                    exceptionHandling.accessDeniedHandler(appAccessDeniedHandler);    // 403异常，携带令牌token，但是权限不够
                })
                // 处理token转换过滤器
                .addFilterAfter(tokenFilter, UsernamePasswordAuthenticationFilter.class)
                .build();
    }


    /**
     * 跨域配置，允许所有来源，所有方法，所有头信息，允许发送Cookie
     * 配置来源（通义千问：security6中配置访问允许跨域请求）
     * @return
     */
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(List.of("*")); // 允许所有来源
        configuration.setAllowedMethods(List.of("*")); // 允许的方法
        configuration.setAllowedHeaders(List.of("*")); // 允许的头信息
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        /*
         * source.registerCorsConfiguration()方法用于将特定的 CORS 配置应用到指定的 URL 路径模式。
         * 这个方法允许你为不同的 URL 路径设置不同的 CORS 策略，从而实现更细粒度的控制
         * */
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}
